import 'dart:async';
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:leader_doctor_flutter/common/http/api.dart';
import 'package:leader_doctor_flutter/common/http/http_client.dart';
import 'package:leader_doctor_flutter/common/utils/log_utils.dart';
import 'package:leader_doctor_flutter/common/utils/string_utils.dart';
import 'package:leader_doctor_flutter/common/widget/comm_widget.dart';
import 'package:leader_doctor_flutter/model/meeting_info.dart';
import 'package:leader_doctor_flutter/model/meeting_role.dart';
import 'package:leader_doctor_flutter/plugins/plugins_messages.g.dart';
import 'package:leader_doctor_flutter/styles/colors.dart';
import 'package:netease_meeting_ui/meeting_ui.dart';
import 'dart:developer' as dev;
import '../../ui/task/meeting/model/result.dart';
import '../../ui/task/meeting/page/meeting_yunxin.dart' as meetingYX;

import '../data/app.dart';

/// @Author lixiaobin
/// @Date 2023/11/30
/// @Description
class MeetingUtils implements NEMeetingAuthListener {
  MeetingUtils._() {
    appKey = App.instance.imAppKey ?? '';
    userId = App.instance.userInfo?.id ?? '';
  }

  static MeetingUtils get instance => _getInstance();
  static MeetingUtils? _instance;

  final NEMeetingKit _neMeetingKit = NEMeetingKit.instance;

  static MeetingUtils _getInstance() {
    _instance ??= MeetingUtils._();
    return _instance!;
  }

  /// 云信appKey
  late String appKey;
  var appName = "领医未来";
  var serverUrl = 'https://roomkit.netease.im/';
  var iosBroadcastAppGroup = 'group.yzns.lyysd';
  late BuildContext context;
  String? mdtId;
  late String userId;
  var userType = 'doctor';
  MeetingInfoModel? infoModel;
  MeetingRoleModel? roleModel;
  bool isStartLive = false;
  NEMeetingStatusListener? _meetingStatusListener;
  DateTime meetingStartDate = DateTime.now();

  ///默认是idle状态，会中内存会记录缓存中。当会议最小化是需要根据版本，不能放入SP，因为会被杀进程。会议需要重新进入。
  int meetingStatus = NEMeetingEvent.idle;

  /// 默认开启白板
  bool openWhiteBoard = true;

  ///是否展示全体视频开/关入口

  var kNoMuteAllVideo = false;

  /// 默认开启录制
  bool kNoCloudRecord = false;

  ///
  var kNoSip = false;

  var kNoMinimize = false;

  /// 画中画
  var kEnablePictureInPicture = true;

  /// 使用默认的短信验证码：081166
  var kUseFakeCheckCode = false;

  /// 配置会议中开启剩余时间提醒
  var kShowMeetingRemainingTip = true;

  /// 开启密码登录
  var kEnablePasswordLogin = !kReleaseMode;

  ///入会
  joinMeeting(BuildContext context, String mdtId) async {
    this.context = context;
    this.mdtId = mdtId;
    Log.d('mdtId>>>$mdtId');
    await EasyLoading.show(
      status: '加载中...',
      maskType: EasyLoadingMaskType.black,
    );
    infoModel = await _getMeetingInfo();
    roleModel = await _getMeetingRole();
    if (infoModel != null && roleModel != null) {
      handleMeetingSdk();
      var model = await _loginMeetingKitWithToken();
      if (model.isSuccess()) {
        var result = await _loginResultSuccess();
        Log.d("result : ${result.code}");
        if (result.code == NEMeetingErrorCode.success) {
          _meetingLog();
          return;
        }
      }
    }
    await logout();
  }

  /// 离开会议
  leaveCurrentMeeting() async {
    await NEMeetingUIKit().leaveCurrentMeeting(false);
  }

  /// 结束最小化
  fullCurrentMeeting() async {
    await NEMeetingUIKit().fullCurrentMeeting();
  }

  /// 获取当前会议详情。如果当前无正在进行中的会议，则回调数据对象为空
  NEMeetingInfo? getCurrentMeetingInfo() {
    return NEMeetingUIKit().getCurrentMeetingInfo();
  }

  Future _loginMeetingKitWithToken() async {
    return _loginProcedure(appKey, () {
      return _neMeetingKit.loginWithToken(
          roleModel?.userUuid ?? '', roleModel?.userToken ?? '');
    });
  }

  logout() async {
    EasyLoading.dismiss();
    await _neMeetingKit.logout();
    if (_meetingStatusListener != null) {
      NEMeetingUIKit().removeListener(_meetingStatusListener!);
    }
    NEMeetingKit.instance.removeAuthListener(this);
    await NativeInterface().finishFlutterContainer();
    dev.log('退出登录');
  }

  FutureOr<Result<void>> _loginResultSuccess() async {
    dev.log("登录成功");
    switch (infoModel?.type ?? '') {
      case 0:
        return _onJoinMeeting();
      case 1:
        roleModel?.toolbarConfig = "0,1,2,5,201,202,121";
        return _onJoinMeeting();
      default:
        return Future(() => Result(code: NEMeetingErrorCode.failed));
    }
  }

  Future<Result<void>> _loginProcedure(
    String appKey,
    Future Function() loginAction,
  ) async {
    final foregroundServiceConfig = NEForegroundServiceConfig(
      contentTitle: appName,
      contentText: '领医未来正在运行中',
      ticker: appName,
      channelId: 'netease_meeting_channel',
      channelName: appName,
      channelDesc: appName,
    );
    await NEMeetingUIKit().switchLanguage(NEMeetingLanguage.chinese);
    final initializeResult = await NEMeetingUIKit().initialize(
      NEMeetingUIKitConfig(
        appKey: appKey,
        appName: appName,
        // useAssetServerConfig: AppConfig().isPrivateEnv,
        iosBroadcastAppGroup: iosBroadcastAppGroup,
        serverUrl: serverUrl,
        extras: null,
        foregroundServiceConfig: foregroundServiceConfig,
      ),
    );
    //点击按钮监听
    NEMeetingUIKit()
        .setOnInjectedMenuItemClickListener((context, clickInfo, meetingInfo) {
      switch (clickInfo.itemId) {
        case 200:
          dev.log("邀请弹窗");
          _buildMeetingInvite();
          break;
        case 201:
          dev.log("录制");
          break;
        case 121:
          dev.log("聊天");
          break;
        case 202:
          dev.log("直播");
          return isStartLive ? _roomKitEndLive() : _roomKitStartLive();
      }
      return Future(() => false);
    });
    dev.log('MeetingSDK initialize result=$initializeResult');
    if (!initializeResult.isSuccess()) {
      return Future(
          () => Result(code: initializeResult.code, msg: initializeResult.msg));
    }
    final loginResult = await loginAction();
    dev.log('MeetingSDK login result=$loginResult');
    return Future(() => Result(code: loginResult.code, msg: loginResult.msg));
  }

  ///toolbar 菜单配置
  List<NEMeetingMenuItem> _getToolbarMenuList(List<String> roleList) {
    var toolbarMenuItems = <NEMeetingMenuItem>[];
    //音频
    if (roleList.contains("0")) {
      toolbarMenuItems.add(NEMenuItems.microphone);
    }
    //视频
    if (roleList.contains("1")) {
      toolbarMenuItems.add(NEMenuItems.camera);
    }
    //屏幕共享权限
    if (roleList.contains("2")) {
      toolbarMenuItems.add(NEMenuItems.screenShare);
    }
    //参会者列表
    if (roleList.contains("3")) {
      toolbarMenuItems.add(NEMenuItems.managerParticipants);
      toolbarMenuItems.add(NEMenuItems.participants);
    }
    //直播-自定义
    if (roleList.contains("202")) {
      toolbarMenuItems.add(const NECheckableMenuItem(
        itemId: 202,
        visibility: NEMenuVisibility.visibleAlways,
        uncheckStateItem: NEMenuItemInfo(
          text: '开始直播',
          icon: 'assets/images/icon_tab_live_unselect.webp',
          platformPackage: '/',
        ),
        checkedStateItem: NEMenuItemInfo(
          text: '结束直播',
          icon: 'assets/images/icon_tab_live_select.webp',
          platformPackage: '/',
        ),
      ));
    }
    //匹配聊天权限
    if (roleList.contains('121')) {
      toolbarMenuItems.add(NEMenuItems.chatroom);
    }
    return toolbarMenuItems;
  }

  ///more 菜单配置
  List<NEMeetingMenuItem> _getMoreMenuList(List<String> roleList) {
    var moreMenuItems = <NEMeetingMenuItem>[];
    //直播-自定义
    if (roleList.contains("200")) {
      moreMenuItems.add(const NESingleStateMenuItem(
        itemId: 200,
        visibility: NEMenuVisibility.visibleAlways,
        singleStateItem: NEMenuItemInfo(
            text: '邀请',
            icon: 'assets/images/icon_tab_home_select.webp',
            platformPackage: '/'),
      ));
    }
    //匹配聊天权限
    if (roleList.contains('21')) {
      moreMenuItems.add(NEMenuItems.chatroom);
    }
    return moreMenuItems;
  }

  Future<NEMeetingUIOptions> _buildMeetingUIOptions({
    bool? noVideo,
    bool? noAudio,
    bool? showMeetingTime,
    bool? noCloudRecord,
    bool? audioAINSEnabled,
    List<NEMeetingMenuItem>? toolbarMenuItems,
    List<NEMeetingMenuItem>? moreMenuItems,
  }) async {
    final settingsService = NEMeetingKit.instance.getSettingsService();
    noVideo ??=
        !(await settingsService.isTurnOnMyVideoWhenJoinMeetingEnabled());
    noAudio ??=
        !(await settingsService.isTurnOnMyAudioWhenJoinMeetingEnabled());
    showMeetingTime ??=
        await settingsService.isShowMyMeetingElapseTimeEnabled();
    // audioAINSEnabled ??= await settingsService.isAudioAINSEnabled();
    noCloudRecord ??= kNoCloudRecord;
    return NEMeetingUIOptions(
      noVideo: noVideo,
      noAudio: noAudio,
      noMuteAllVideo: kNoMuteAllVideo,
      noWhiteBoard: !openWhiteBoard,
      noSip: kNoSip,
      noLive: true,
      noCloudRecord: noCloudRecord,
      showMeetingTime: showMeetingTime,
      noMinimize: kNoMinimize,
      enablePictureInPicture: kEnablePictureInPicture,
      // audioAINSEnabled: audioAINSEnabled,
      showMeetingRemainingTip: kShowMeetingRemainingTip,
      restorePreferredOrientations: [DeviceOrientation.portraitUp],
      injectedToolbarMenuItems: toolbarMenuItems,
      injectedMoreMenuItems: moreMenuItems,
      extras: {
        'shareScreenTips':
            "您屏幕上包括通知在内的所有内容，均将被录制。请警惕仿冒客服、校园贷和公检法的诈骗，不要在“共享屏幕”时进行财务转账操作。"
      },
    );
  }

  Future<Result<void>> _onJoinMeeting() async {
    var displayName = roleModel?.nickName ?? "";
    var targetMeetingNum = infoModel?.meetingNum ?? "";
    var roleList = roleModel?.toolbarConfig?.split(",") ?? <String>[];
    var toolbarMenuList = _getToolbarMenuList(roleList);
    var moreMenuList = _getMoreMenuList(roleList);
    //shareScreenTips 屏幕弹窗提示共享文案
    if (!context.mounted) return Future(() => Result<void>(code: 1, msg: ''));
    final result = await NEMeetingUIKit().joinMeetingUI(
      context,
      NEJoinMeetingUIParams(
          meetingNum: targetMeetingNum, displayName: displayName),
      await _buildMeetingUIOptions(
          noVideo: true,
          noAudio: true,
          showMeetingTime: false,
          noCloudRecord: true,
          toolbarMenuItems: toolbarMenuList,
          moreMenuItems: moreMenuList),
      onPasswordPageRouteWillPush: () async {
        EasyLoading.dismiss();
      },
      onMeetingPageRouteWillPush: () async {
        EasyLoading.dismiss();
        // if (!context.mounted) return;
        // Navigator.of(context).pop();
      },
      // backgroundWidget: const meetingYX.MeetingPage(),
    );
    if (!context.mounted) return Future(() => Result<void>(code: 1, msg: ''));
    final errorCode = result.code;
    final errorMessage = result.msg;
    EasyLoading.dismiss();
    if (errorCode == NEMeetingErrorCode.success) {
    } else if (errorCode == NEMeetingErrorCode.noNetwork) {
      _showToast('网络连接失败，请检查你的网络连接！');
    } else if (errorCode == NEMeetingErrorCode.noAuth) {
      _showToast('同时登录设备数超出限制，已自动登出');
    } else if (errorCode == NEMeetingErrorCode.alreadyInMeeting) {
      _showToast('会议中暂不支持该操作');
    } else if (errorCode == NEMeetingErrorCode.cancelled) {
      /// 暂不处理
      dev.log('暂不处理');
    } else {
      var errorTips = getMsg(errorMessage, '加入会议失败');
      _showToast(errorTips);
    }
    return Future(() => Result<void>(code: errorCode, msg: errorMessage));
  }

  _showToast(String msg) {
    NativeInterface().toast(msg);
  }

  void handleMeetingSdk() {
    _meetingStatusListener = (status) {
      meetingStatus = status.event;
      NativeInterface().notifyMeetingStatusChanged(meetingStatus, status.arg);
      switch (meetingStatus) {
        case NEMeetingEvent.disconnecting:
          switch (status.arg) {
            case NEMeetingCode.closeByHost:

              /// 主持人关闭会议
              break;
            case NEMeetingCode.authInfoExpired:

              /// 认证过期
              _showToast('网络异常，请检查网络连接后重新入会');
              break;

            case NEMeetingCode.endOfLife:

              /// 会议时长超限
              _showToast('会议时长已达上限，会议关闭');
              break;

            case NEMeetingCode.loginOnOtherDevice:

              /// 账号再其他设备入会
              _showToast('因被主持人移出或切换至其他设备，您已退出会议');
              break;

            case NEMeetingCode.syncDataError:

              /// 同步数据失败
              _showToast('房间信息同步失败');
              break;

            // case NEMeetingCode.removedByHost: /// 被主持人移除会议
            //   _showToast( Strings.removedByHost);
            //   break;
          }
          logout();
          break;
        case NEMeetingEvent.inMeeting:
          var meetingInfo = NEMeetingUIKit().getCurrentMeetingInfo();
          // 记录在会 开始时间
          meetingStartDate = DateTime.now();
          break;
        default:
      }
    };
    NEMeetingUIKit().addListener(_meetingStatusListener!);
    NEMeetingKit.instance.addAuthListener(this);
  }

  static String getMsg(String? msg, [String? defaultMsg]) {
    if (msg == null || msg.isEmpty) {
      return (defaultMsg == null || defaultMsg.isEmpty)
          ? '网络连接失败，请检查你的网络连接！'
          : defaultMsg;
    }
    return msg;
  }

  ///获取会议详情
  Future<MeetingInfoModel?> _getMeetingInfo() async {
    var httpRequest = HttpRequest(Api.meetingInfo, isShowLoading: false, body: {
      'mdtId': mdtId,
      "userId": userId,
      "userType": userType,
    });
    var httpResponse = await HttpClient.postJson(httpRequest);
    var serviceResult = ServiceResult<MeetingInfoModel?>(
        httpResponse, (map) => MeetingInfoModel.fromJson(map));
    if (!serviceResult.success) {
      _showToast(serviceResult.responseMsg ?? '');
    }
    return serviceResult.responseBody;
  }

  ///获取会议角色权限
  Future<MeetingRoleModel?> _getMeetingRole() async {
    var httpRequest =
        HttpRequest(Api.meetingAccount, isShowLoading: false, body: {
      'mdtId': mdtId,
      "userId": userId,
      "userType": userType,
    });
    var httpResponse = await HttpClient.postJson(httpRequest);
    var serviceResult = ServiceResult<MeetingRoleModel?>(
        httpResponse, (map) => MeetingRoleModel.fromJson(map));
    if (!serviceResult.success) {
      _showToast(serviceResult.responseMsg ?? '');
    }
    return serviceResult.responseBody;
  }

  ///设置直播开播状态--结束
  Future<bool> _roomKitEndLive() async {
    var httpRequest = HttpRequest(Api.roomKitEndLive, body: {
      'id': infoModel?.id.toString(),
      "meetingNum": infoModel?.meetingNum,
      'userUuid': userId,
    });
    var httpResponse = await HttpClient.postJson(httpRequest);
    var serviceResult = ServiceResult<String?>.simple(httpResponse);
    if (serviceResult.success) {
      isStartLive = false;
      return Future(() => true);
    } else {
      var responseMsg = serviceResult.responseMsg;
      if (StringUtils.isNotEmpty(responseMsg)) {
        Fluttertoast.showToast(msg: responseMsg ?? '');
      }
      return Future(() => false);
    }
  }

  ///入会日志
  _meetingLog() async {
    var deviceInfo = App.instance.deviceInfo;
    var packageInfo = App.instance.packageInfo;
    var httpRequest = HttpRequest(Api.addMeetingLog, body: {
      'id': infoModel?.id?.toString(),
      'userId': userId,
      "memberId": roleModel?.id,
      "userUuid": roleModel?.userUuid,
      "mdtId": infoModel?.id,
      "appEntry": 'lywl',
      "mobileModel": deviceInfo?.brand,
      "mobileModelCode": deviceInfo?.deviceModel,
      "appVersion": packageInfo?.appVersionName,
    });
    var httpResponse = await HttpClient.postJson(httpRequest);
    var serviceResult = ServiceResult<String?>.simple(httpResponse);
    if (!serviceResult.success) {
      Fluttertoast.showToast(msg: serviceResult.responseMsg ?? '');
    }
    //会议入会后提醒用户打开摄像头麦克风
    if (infoModel?.type == 0) {
      Future.delayed(const Duration(seconds: 2), () {
        _showToast('为了更好的参会体验，请打开麦克风和摄像头');
      });
    }
  }

  ///设置直播开播状态--开始
  Future<bool> _roomKitStartLive() async {
    var httpRequest = HttpRequest(Api.roomKitStartLive, body: {
      'id': infoModel?.id?.toString(),
      "meetingNum": infoModel?.meetingNum,
      'userUuid': userId,
    });
    var httpResponse = await HttpClient.postJson(httpRequest);
    var serviceResult = ServiceResult<String?>.simple(httpResponse);
    if (serviceResult.success) {
      isStartLive = true;
      return Future(() => true);
    } else {
      _buildAlertInvite(serviceResult.responseMsg);
      return Future(() => false);
    }
  }

  @override
  void onAuthInfoExpired() {
    //如果处于会议中，先等会议页面pop完成，在弹窗
    //合理的做法是从meeting_page一路把错误传出来，但修改密码的场景本来就非高频场景
    //这里暂时delay一段时间，等待pop完成后，在弹窗
    //如果当前不是会议场景，没有必要进行delay
    logout();
    _showToast('登录状态已过期，请重新登录');
  }

  @override
  void onKickOut() {
    logout();
    _showToast('同时登录设备数超出限制，已自动登出');
  }

  _buildMeetingInvite() {
    return CommWidget.buildBottomSheetDialog(context,
        title: '会议邀请',
        buildView: (c) => Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text('会议主题：',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      color: ColorRes.color333333,
                    )),
                SizedBox(
                  height: 5.w,
                ),
                Text(infoModel?.title ?? '',
                    style: const TextStyle(
                      color: ColorRes.color333333,
                    )),
                SizedBox(
                  height: 5.w,
                ),
                const Text('会议地址：',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      color: ColorRes.color333333,
                    )),
                SizedBox(
                  height: 5.w,
                ),
                Text(roleModel?.invitationLink ?? '',
                    style: const TextStyle(
                      color: ColorRes.colorMain,
                    )),
                SizedBox(
                  height: 40.w,
                ),
                CommWidget.buildRightBtn('复制邀请', () {
                  var str =
                      "会议主题：${infoModel?.title}\n\n点击加入会议：\n${roleModel?.invitationLink}";
                  Clipboard.setData(ClipboardData(text: str));
                  _showToast('复制成功');
                  Navigator.of(c).pop();
                }),
              ],
            ));
  }

  _buildAlertInvite(String? msg) {
    return CommWidget.buildBottomSheetDialog(context,
        title: '温馨提示',
        buildView: (c) => Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(msg ?? '系统检测到你还未开启摄像头，请先点击"开启视频"按钮后在开始直播',
                    style: TextStyle(
                        color: ColorRes.color333333, fontSize: 16.sp)),
                SizedBox(
                  height: 40.w,
                ),
                CommWidget.buildRightBtn('知道了', () {
                  Navigator.of(c).pop();
                }),
              ],
            ));
  }
}
